package org.springframework.aop;

import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.framework.AdvisorChainFactory;
import org.springframework.aop.framework.DefaultAdvisorChainFactory;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 配置和管理AOP代理的类 封装了很多的目标对象的代理方法
 */
public class AdvisedSupport {


    //是否使用cglib代理
    private boolean proxyTargetClass = true;
    //被代理的目标对象
    private TargetSource targetSource;
    //拦截器，通过拦截器来调用增强目标对象的方法
    private MethodInterceptor methodInterceptor;
    //方法的匹配器,匹配对于代理对象的哪个方法是需要代理增强的
    private MethodMatcher methodMatcher;

    //方法缓存区 这里的key是方法的hashcode值 而value是该方法的拦截器链
    private transient Map<Integer, List<Object>> methodCache;

    //代理链的获取工厂
    AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();

    //advisor的集合 advisor是封装Advice的重要类
    private List<Advisor> advisors = new ArrayList<>();

    public AdvisedSupport() {
        this.methodCache = new ConcurrentHashMap<>(32);
    }

    public boolean isProxyTargetClass() {
        return proxyTargetClass;
    }

    public void setProxyTargetClass(boolean proxyTargetClass) {
        this.proxyTargetClass = proxyTargetClass;
    }

    public void addAdvisor(Advisor advisor) {
        advisors.add(advisor);
    }

    public List<Advisor> getAdvisors() {
        return advisors;
    }

    public TargetSource getTargetSource() {
        return targetSource;
    }

    public void setTargetSource(TargetSource targetSource) {
        this.targetSource = targetSource;
    }


    public MethodMatcher getMethodMatcher() {
        return methodMatcher;
    }

    public void setMethodMatcher(MethodMatcher methodMatcher) {
        this.methodMatcher = methodMatcher;
    }

    /**
     * 用来返回方法的拦截器链
     */
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
        Integer cacheKey = method.hashCode();
        List<Object> cached = this.methodCache.get(cacheKey);
        //如果没有找到缓存里的拦截器链就通过拦截器链工厂获取 并存入缓存
        if (cached == null) {
            cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                    this, method, targetClass);
            this.methodCache.put(cacheKey, cached);
        }
        return cached;
    }


}
